a tool for shared writing and social publishing
at feature/recommend 64 lines 2.1 kB view raw
1import { NextResponse } from "next/server"; 2import { DidResolver } from "@atproto/identity"; 3import { parseReqNsid, verifyJwt } from "@atproto/xrpc-server"; 4import { supabaseServerClient } from "supabase/serverClient"; 5import { 6 normalizeDocumentRecord, 7 type NormalizedDocument, 8} from "src/utils/normalizeRecords"; 9 10const serviceDid = "did:web:leaflet.pub:lish:feeds"; 11export async function GET( 12 req: Request, 13 { params }: { params: Promise<{ path: string[] }> }, 14) { 15 let { path } = await params; 16 if (path[0] === "did.json") 17 return NextResponse.json({ 18 "@context": ["https://www.w3.org/ns/did/v1"], 19 id: serviceDid, 20 service: [ 21 { 22 id: "#bsky_fg", 23 type: "BskyFeedGenerator", 24 serviceEndpoint: `https://leaflet.pub/lish/feeds`, 25 }, 26 ], 27 }); 28 let auth = validateAuth(req, serviceDid); 29 if (!auth) return NextResponse.json({}, { status: 301 }); 30 let { data: publications } = await supabaseServerClient 31 .from("publication_subscriptions") 32 .select(`publications(documents_in_publications(documents(*)))`) 33 .eq("identity", auth); 34 return NextResponse.json({ 35 feed: [ 36 ...(publications || []).flatMap((pub) => { 37 let posts = pub.publications?.documents_in_publications || []; 38 return posts.flatMap((p) => { 39 if (!p.documents?.data) return []; 40 const normalizedDoc = normalizeDocumentRecord(p.documents.data, p.documents.uri); 41 if (!normalizedDoc?.bskyPostRef) return []; 42 return { post: normalizedDoc.bskyPostRef.uri }; 43 }); 44 }), 45 ], 46 }); 47} 48 49const didResolver = new DidResolver({}); 50const validateAuth = async ( 51 req: Request, 52 serviceDid: string, 53): Promise<string | null> => { 54 const authorization = req.headers.get("authorization"); 55 if (!authorization?.startsWith("Bearer ")) { 56 return null; 57 } 58 const jwt = authorization.replace("Bearer ", "").trim(); 59 const nsid = parseReqNsid(req); 60 const parsed = await verifyJwt(jwt, serviceDid, nsid, async (did: string) => { 61 return didResolver.resolveAtprotoKey(did); 62 }); 63 return parsed.iss; 64};